<?php
/**
 * DBERP 进销存系统
 *
 * ==========================================================================
 * @link      http://www.dberp.net/
 * @copyright 北京珑大钜商科技有限公司，并保留所有权利。
 * @license   http://www.dberp.net/license.html License
 * ==========================================================================
 *
 * @author    静静的风 <baron@loongdom.cn>
 *
 */

namespace Extend\Controller;

use Admin\AdminTrait\AdminTrait;
use Admin\Data\Common;
use Admin\Data\Config;
use Extend\Entity\Plugin;
use Extend\Service\PluginManager;
use Doctrine\ORM\EntityManager;
use Laminas\Config\Factory;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\Mvc\I18n\Translator;
use Laminas\View\Model\JsonModel;

class IndexController extends AbstractActionController
{
    use AdminTrait;

    private $translator;
    private $entityManager;
    private $pluginManager;

    public function __construct(
        Translator $translator,
        EntityManager $entityManager,
        PluginManager $pluginManager
    )
    {
        $this->translator       = $translator;
        $this->entityManager    = $entityManager;
        $this->pluginManager    = $pluginManager;
    }

    /**
     * 插件列表
     * @return array|\Laminas\View\Model\ViewModel
     */
    public function indexAction()
    {
        $pluginList = $this->entityManager->getRepository(Plugin::class)->findBy([], ['pluginId' => 'ASC']);

        $pluginCodeArray = [];
        if ($pluginList) foreach ($pluginList as $pluginValue) {
            $pluginCodeArray[] = $pluginValue->getPluginCode();
        }
        $updatePlugin = [];
        if (!empty($pluginCodeArray)) {
            $result = $this->adminCommon()->dberpApiService('erpPluginUpdateList', ['pluginCode' => $pluginCodeArray]);
            if (isset($result['result']['updatePlugin'])) $updatePlugin = $result['result']['updatePlugin'];
        }

        return [
            'pluginList'        => $pluginList,
            'pluginImagePath'   => Config::PLUGIN_IMAGE_URL,

            'updatePlugin'      => $updatePlugin
        ];
    }

    /**
     * 可安装插件列表
     * @return array|\Laminas\Http\Response
     */
    public function pluginListAction()
    {
        $result = $this->adminCommon()->dberpApiService('erpPluginList');
        if ($result == null) return $this->redirect()->toRoute('service-bind');

        $pluginList = $this->entityManager->getRepository(Plugin::class)->findBy([]);
        $pluginCodeArray = [];
        if ($pluginList) foreach ($pluginList as $pValue) {
            $pluginCodeArray[] = $pValue->getPluginCode();
        }

        return [
            'serviceUrl'    => Config::SERVICE_URL,
            'result'        => $result,
            'pluginCodeArray' => $pluginCodeArray
        ];
    }

    /**
     * 启用插件
     * @return JsonModel
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function onPluginAction()
    {
        $pluginCode = $this->params()->fromPost('pluginCode');
        if (empty($pluginCode)) return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('插件编码为空！')]);

        $pluginInfo = $this->entityManager->getRepository(Plugin::class)->findOneBy(['pluginCode' => $pluginCode, 'pluginState' => 0]);
        if ($pluginInfo == null) return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('插件已经启用或者该插件不存在！')]);

        $pluginPath     = 'module/Plugin/' . $pluginInfo->getPluginCode();
        $pluginIniPath  = 'data/moduleData/Plugin/';
        if (is_dir($pluginPath)) {
            //后台url
            if (file_exists($pluginPath . '/data/url/admin.php')) {
                $adminUrlArray  = Factory::fromFile($pluginPath . '/data/url/admin.php');
                $adminUrlIni    = Factory::fromFile($pluginIniPath . 'adminUrl.ini');
                if (!empty($adminUrlArray)) {
                    $adminUrlIni[$adminUrlArray['place']][$pluginCode]  = $adminUrlArray[$adminUrlArray['place']];
                    $adminUrlIni[$adminUrlArray['place'].'Module'][]    = $pluginCode;
                    $adminUrlIni[$adminUrlArray['place'].'Module']      = array_unique($adminUrlIni[$adminUrlArray['place'].'Module']);
                }
                Factory::toFile($pluginIniPath . 'adminUrl.ini', $adminUrlIni);
            }
            //前台url
            if (file_exists($pluginPath . '/data/url/shop.php')) {
                $shopUrlArray   = Factory::fromFile($pluginPath . '/data/url/shop.php');
                $shopUrlIni     = Factory::fromFile($pluginIniPath . 'shopUrl.ini');
                if (!empty($shopUrlArray)) {
                    $shopUrlIni[$shopUrlArray['place']][$pluginCode] = $shopUrlArray[$shopUrlArray['place']];
                    $shopUrlIni[$shopUrlArray['place'].'Module'][]    = $pluginCode;
                    $shopUrlIni[$shopUrlArray['place'].'Module']      = array_unique($shopUrlIni[$shopUrlArray['place'].'Module']);
                }
                Factory::toFile($pluginIniPath . 'shopUrl.ini', $shopUrlIni);
            }
            //检查是否有需要拷贝到其他目录的文件
            if (file_exists($pluginPath . '/data/copyFile.php')) {
                $copyFileArray = Factory::fromFile($pluginPath . '/data/copyFile.php');
                if (is_array($copyFileArray) && !empty($copyFileArray)) {
                    foreach ($copyFileArray as $fileValue) {
                        if (isset($fileValue['copy']) && isset($fileValue['copyTo']) && file_exists($pluginPath . $fileValue['copy'])) {
                            $copyToPath = dirname($fileValue['copyTo']);
                            if (!is_dir($copyToPath)) mkdir(rtrim($copyToPath, '/'), 0755, true);
                            if (!copy($pluginPath . $fileValue['copy'], $fileValue['copyTo'])) return new JsonModel(['state' => 'false', 'message' => sprintf($this->translator->translate('无法正常安装文件，请检查%s对应的目录是否有相关权限'), $fileValue['copyTo'])]);
                        }
                    }
                }
            }
            //判断插件是否需要设置模块运行
            if (!file_exists($pluginPath . '/data/noModule.php')) {
                $moduleExtend = Common::readConfigFile('moduleExtend');
                $pluginModule = Common::readConfigFile('pluginModule');

                $moduleExtend[$pluginCode] = ['key' => $pluginCode . "\\", 'value' => 'module/Plugin/' . $pluginCode . '/src/'];
                $pluginModule[] = $pluginCode;
                $pluginModule   = array_unique($pluginModule);

                Common::writeConfigFile('moduleExtend', $moduleExtend);
                Common::writeConfigFile('pluginModule', $pluginModule);
            }
            //更新缓存
            Common::deleteDirAndFile('data/cache', false);
            Common::opcacheReset();
            //修改数据库中信息
            $this->pluginManager->editPlugin(['pluginState' => 1], $pluginInfo);

            return new JsonModel(['state' => 'true', 'message' => $this->translator->translate('插件启用成功')]);
        }
        return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('插件启用失败！')]);
    }

    /**
     * 停用插件
     * @return JsonModel
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function offPluginAction()
    {
        $pluginCode = $this->params()->fromPost('pluginCode');
        if (empty($pluginCode)) return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('插件编码为空！')]);

        $pluginInfo = $this->entityManager->getRepository(Plugin::class)->findOneBy(['pluginCode' => $pluginCode, 'pluginState' => 1]);
        if ($pluginInfo == null) return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('插件已经关闭或者该插件不存在！')]);

        $pluginPath     = 'module/Plugin/' . $pluginInfo->getPluginCode();
        $pluginIniPath  = 'data/moduleData/Plugin/';
        if (is_dir($pluginPath)) {
            //后台url
            if (file_exists($pluginPath . '/data/url/admin.php')) {
                $adminUrlArray  = Factory::fromFile($pluginPath . '/data/url/admin.php');
                $adminUrlIni    = Factory::fromFile($pluginIniPath . 'adminUrl.ini');
                $mKey = array_search($pluginCode, $adminUrlIni[$adminUrlArray['place'].'Module']);
                if ($mKey >= 0 && $adminUrlIni[$adminUrlArray['place'].'Module'][$mKey] == $pluginCode) {
                    unset($adminUrlIni[$adminUrlArray['place'].'Module'][$mKey]);
                    sort($adminUrlIni[$adminUrlArray['place'].'Module']);
                }
                if (isset($adminUrlIni[$adminUrlArray['place']][$pluginCode])) unset($adminUrlIni[$adminUrlArray['place']][$pluginCode]);
                Factory::toFile($pluginIniPath . 'adminUrl.ini', $adminUrlIni);
            }
            //前台url
            if (file_exists($pluginPath . '/data/url/shop.php')) {
                $shopUrlArray   = Factory::fromFile($pluginPath . '/data/url/shop.php');
                $shopUrlIni     = Factory::fromFile($pluginIniPath . 'shopUrl.ini');
                $mKey = array_search($pluginCode, $shopUrlIni[$shopUrlArray['place'].'Module']);
                if ($mKey >= 0 && $shopUrlIni[$shopUrlArray['place'].'Module'][$mKey] == $pluginCode) {
                    unset($shopUrlIni[$shopUrlArray['place'].'Module'][$mKey]);
                    sort($shopUrlIni[$shopUrlArray['place'].'Module']);
                }
                if (isset($shopUrlIni[$shopUrlArray['place']][$pluginCode])) unset($shopUrlIni[$shopUrlArray['place']][$pluginCode]);
                Factory::toFile($pluginIniPath . 'shopUrl.ini', $shopUrlIni);
            }
            //检查是否有需要删除其他目录的文件
            if (file_exists($pluginPath . '/data/delFile.php')) {
                $delFileArray = Factory::fromFile($pluginPath . '/data/delFile.php');
                if (is_array($delFileArray) && !empty($delFileArray)) {
                    foreach ($delFileArray as $delFile) {
                        if (file_exists($delFile)) @unlink($delFile);
                    }
                }
            }
            //判断插件的data目录是否有noModule.php文件
            if (!file_exists($pluginPath . '/data/noModule.php')) {
                $moduleExtend = Common::readConfigFile('moduleExtend');
                $pluginModule = Common::readConfigFile('pluginModule');

                if (isset($moduleExtend[$pluginCode])) unset($moduleExtend[$pluginCode]);
                $key = array_search($pluginCode, $pluginModule);
                if ($pluginModule[$key] == $pluginCode) unset($pluginModule[$key]);

                Common::writeConfigFile('moduleExtend', $moduleExtend);
                Common::writeConfigFile('pluginModule', $pluginModule);
            }
            //更新缓存
            Common::deleteDirAndFile('data/cache', false);
            Common::opcacheReset();
            //修改数据库中信息
            $pluginInfo = $this->pluginManager->editPlugin(['pluginState' => 0], $pluginInfo);

            $this->getEventManager()->trigger('extend-plugin.off.post', $this, ['pluginInfo' => $pluginInfo]);

            return new JsonModel(['state' => 'true', 'message' => $this->translator->translate('插件停用成功')]);
        }
        return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('插件停用失败！')]);
    }

    /**
     * 插件安装处理
     * @return JsonModel
     * @throws \Doctrine\DBAL\Driver\Exception
     * @throws \Doctrine\DBAL\Exception
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function startInstallPluginAction()
    {
        $pluginCode = $this->params()->fromPost('pluginCode');
        if (!empty($pluginCode)) {
            $pluginInfo = $this->entityManager->getRepository(Plugin::class)->findOneBy(['pluginCode' => $pluginCode]);
            if ($pluginInfo) {
                return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('该插件您已经安装，无需再次安装！')]);
            }

            $result = $this->adminCommon()->dberpApiService('erpPluginInfo', ['pluginCode' => $pluginCode]);
            if (
                !$result
                || ($result['code'] == 200 && empty($result['result']))
                || $result['code'] == 400
            )  return new JsonModel(['state' => 'false', 'message' => !empty($result['message']) ? $result['message'] : $this->translator->translate('插件包信息错误，无法进行安装。可能原因：本地测试安装。')]);

            $packageInfo = $this->onlineOperationPackage($result['result']['pluginInfo'], ['pluginCode' => $pluginCode], 'plugin');
            if (isset($packageInfo['state']) && $packageInfo['state'] == 'false' && $packageInfo['message']) return new JsonModel($packageInfo);

            //更新缓存
            Common::deleteDirAndFile('data/cache', false);
            Common::opcacheReset();

            $this->pluginManager->addPlugin([
                'pluginName'        => $packageInfo['pluginName'],
                'pluginAuthor'      => $packageInfo['pluginAuthor'],
                'pluginAuthorUrl'   => $packageInfo['pluginAuthorUrl'],
                'pluginInfo'        => $packageInfo['pluginInfo'],
                'pluginVersion'     => $packageInfo['pluginVersion'],
                'pluginVersionNum'  => $packageInfo['pluginVersionNum'],
                'pluginCode'        => $packageInfo['pluginCode'],
                'pluginSupportUrl'  => $packageInfo['pluginSupportUrl'],
                'pluginAdminPath'   => $packageInfo['pluginAdminPath'],
                'pluginUpdateTime'  => date("Y-m-d")
            ]);

            $this->adminCommon()->addOperLog(sprintf($this->translator->translate('插件 %s 安装完成!'), $packageInfo['pluginName']), $this->translator->translate('扩展插件'));

            return new JsonModel(['state' => 'true', 'message' => $this->translator->translate('插件安装完成')]);
        }
        return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('信息不完整')]);
    }

    /**
     * 插件更新包安装处理
     * @return JsonModel
     * @throws \Doctrine\DBAL\Driver\Exception
     * @throws \Doctrine\DBAL\Exception
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function startUpdatePluginAction()
    {
        $pluginCode = $this->params()->fromPost('pluginCode');
        if (!empty($pluginCode)) {
            $pluginInfo = $this->entityManager->getRepository(Plugin::class)->findOneBy(['pluginCode' => $pluginCode]);
            if (!$pluginInfo) {
                return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('该插件未安装，不能进行更新！')]);
            }

            $result = $this->adminCommon()->dberpApiService('erpPluginVersionInfo', ['pluginCode' => $pluginCode, 'pluginVersionNum' => $pluginInfo->getPluginVersionNum()]);
            if (
                !$result
                || ($result['code'] == 200 && empty($result['result']))
                || $result['code'] == 400
            )  return new JsonModel(['state' => 'false', 'message' => !empty($result['message']) ? $result['message'] : $this->translator->translate('插件更新包信息错误，无法进行更新。可能原因：本地测试更新。')]);

            $packageInfo    = $result['result']['pluginVersionInfo'];
            $packageInfo    = $this->onlineOperationPackage($packageInfo, ['pluginCode' => $pluginCode, 'pluginId' => $packageInfo['pluginId'], 'pluginVersionId' => $packageInfo['pluginVersionId']], 'updatePlugin');
            if (isset($packageInfo['state']) && $packageInfo['state'] == 'false' && $packageInfo['message']) return new JsonModel($packageInfo);

            //当该插件处于启动状态时
            $pluginPath     = 'module/Plugin/' . $pluginInfo->getPluginCode();
            if ($pluginInfo->getPluginState() == 1) {
                //检查是否有需要拷贝到其他目录的文件
                if (file_exists($pluginPath . '/data/updateCopyFile.php')) {
                    $copyFileArray = Factory::fromFile($pluginPath . '/data/updateCopyFile.php');
                    if (is_array($copyFileArray) && !empty($copyFileArray)) {
                        foreach ($copyFileArray as $fileValue) {
                            if (isset($fileValue['copy']) && isset($fileValue['copyTo']) && file_exists($pluginPath . $fileValue['copy'])) {
                                $copyToPath = dirname($fileValue['copyTo']);
                                if (!is_dir($copyToPath)) mkdir(rtrim($copyToPath, '/'), 0755, true);
                                if (!copy($pluginPath . $fileValue['copy'], $fileValue['copyTo'])) return new JsonModel(['state' => 'false', 'message' => sprintf($this->translator->translate('无法正常更新该插件，请检查%s对应的目录是否有相关权限'), $fileValue['copyTo'])]);
                            }
                        }
                    }
                }

                $pluginIniPath  = 'data/moduleData/Plugin/';
                //后台url
                if (file_exists($pluginPath . '/data/url/admin.php')) {
                    $adminUrlArray  = Factory::fromFile($pluginPath . '/data/url/admin.php');
                    $adminUrlIni    = Factory::fromFile($pluginIniPath . 'adminUrl.ini');
                    if (!empty($adminUrlArray)) {
                        $adminUrlIni[$adminUrlArray['place']][$pluginCode]  = $adminUrlArray[$adminUrlArray['place']];
                        $adminUrlIni[$adminUrlArray['place'].'Module'][]    = $pluginCode;
                        $adminUrlIni[$adminUrlArray['place'].'Module']      = array_unique($adminUrlIni[$adminUrlArray['place'].'Module']);
                    }
                    Factory::toFile($pluginIniPath . 'adminUrl.ini', $adminUrlIni);
                }
                //前台url
                if (file_exists($pluginPath . '/data/url/shop.php')) {
                    $shopUrlArray   = Factory::fromFile($pluginPath . '/data/url/shop.php');
                    $shopUrlIni     = Factory::fromFile($pluginIniPath . 'shopUrl.ini');
                    if (!empty($shopUrlArray)) {
                        $shopUrlIni[$shopUrlArray['place']][$pluginCode] = $shopUrlArray[$shopUrlArray['place']];
                        $shopUrlIni[$shopUrlArray['place'].'Module'][]    = $pluginCode;
                        $shopUrlIni[$shopUrlArray['place'].'Module']      = array_unique($shopUrlIni[$shopUrlArray['place'].'Module']);
                    }
                    Factory::toFile($pluginIniPath . 'shopUrl.ini', $shopUrlIni);
                }
            }
            if (file_exists($pluginPath . '/data/updateCopyFile.php')) @unlink($pluginPath . '/data/updateCopyFile.php');

            //更新缓存
            Common::deleteDirAndFile('data/cache', false);
            Common::opcacheReset();

            $this->pluginManager->editPlugin([
                'pluginName'        => $packageInfo['pluginName'],
                'pluginAuthor'      => $packageInfo['pluginAuthor'],
                'pluginAuthorUrl'   => $packageInfo['pluginAuthorUrl'],
                'pluginInfo'        => $packageInfo['pluginInfo'],
                'pluginVersion'     => $packageInfo['pluginVersionName'],
                'pluginVersionNum'  => $packageInfo['pluginVersionNum'],
                'pluginSupportUrl'  => $packageInfo['pluginSupportUrl'],
                'pluginAdminPath'   => $packageInfo['pluginAdminPath'],
                'pluginUpdateTime'  => date("Y-m-d")
            ], $pluginInfo);

            $this->adminCommon()->addOperLog(sprintf($this->translator->translate('插件 %s 更新完成!'), $packageInfo['pluginName']), $this->translator->translate('扩展插件'));

            return new JsonModel(['state' => 'true', 'message' => $this->translator->translate('插件更新完成')]);
        }
        return new JsonModel(['state' => 'false', 'message' => $this->translator->translate('信息不完整')]);
    }
}